/*
    Copyright 2006-2011 Patrik Jonsson, sunrise@familjenjonsson.org

    This file is part of Sunrise.

    Sunrise is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.

    Sunrise is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Sunrise.  If not, see <http://www.gnu.org/licenses/>.

*/

/// \file
/// Definitions of random number functions.

// $Id$

#include "random.h"
#include "random/discrete-uniform.h"
#include "blitz/numinquire.h"

/** This is the unique instance of the mcrx_random random number
    generator used. */
mcrx::mutex_random mcrx::mcrx_random;

boost::mutex mcrx::mutex_random::mutex;

/** Returns a random number, locking the mutex. */
mcrx::T_float mcrx::mutex_random::random () {
  boost::mutex::scoped_lock lock (mutex);
  return generator.random();
}

/** Seeds the random number generator, locking the mutex. */
void mcrx::mutex_random::seed (unsigned int s) {
  boost::mutex::scoped_lock lock (mutex);
  generator.seed(s );
}

/** Returns a random number from the "global" mcrx_random
    generator. */
mcrx::T_float mcrx::rnd () {return mcrx_random.random();}


/** Seeds the "global" mcrx_random generator. */
void mcrx::seed (unsigned int s) {mcrx_random.seed(s );}


/** Generates a random state vector with n entries by seeding a
    (independent) generator using the shared state.  Hence, the state
    vector generated can be changed with seed ().  This routine is
    used to generate initial states when multithreading, since in
    those cases each thread has its own random number generator. */
std::vector<mcrx::T_rng::T_state> mcrx::generate_random_states (int n)
{
  // independent generator that we will use to capture its state
  T_rng generator;
  // shared generator we will use to draw a seed for the independent one
  const unsigned int u = 0;
  ranlib::DiscreteUniform<unsigned int> seeder (blitz::huge (u)-1);
  std::vector<T_rng::T_state> state;
  std::vector<int> junk;
  for (int i = 0; i < n; ++i) {
    generator.seed(seeder.random() );
    const T_rng::T_state s=generator.getState();
    state.push_back(s );
  }
  return state;
}
